package panel;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import util.*;

import javax.swing.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

/**
 * 项目初始化
 * 写入一些基础依赖，生成必要代码
 */
public class InitProjectPanel extends JPanel {
    private Project project;
    JTextField appName, themeColor, author;
    JRadioButton codeJB, libJB;
    //appId
    private String appId;
    //app根路径（com.aa.aa）
    private String appPath;

    private AnActionEvent event;

    private CloseListener closeListener;

    public InitProjectPanel(AnActionEvent event, CloseListener closeListener) {
        this.event = event;
        this.closeListener = closeListener;
        project = event.getData(PlatformDataKeys.PROJECT);
        initDirPath();
        initView();
    }

    private void initDirPath() {
        appId = PathUtil.readApplicationId(project);
        appPath = project.getBasePath() + "/app/src/main/java/" + appId.replace(".", "/") + "/";
    }

    private void initView() {
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel panelName = new JPanel();// /定义一个面板
        panelName.setLayout(new GridLayout(2, 2));
        panelName.setBorder(BorderFactory.createTitledBorder("APP设置"));
        appName = new JTextField("APP名称");
        panelName.add(appName);
        themeColor = new JTextField("主题颜色(例如:#FFFFFF)");
        panelName.add(themeColor);
        author = new JTextField("作者");
        panelName.add(author);
        add(panelName);

        codeJB = new JRadioButton("源代码方式");// 定义一个单选按钮
        libJB = new JRadioButton("jar方式");// 定义一个单选按钮

        libJB.setSelected(true);

        JPanel panel = new JPanel();// /定义一个面板

        panel.setBorder(BorderFactory.createTitledBorder("选择基础库引入方式"));// 定义一个面板的边框显示条
        panel.setLayout(new GridLayout(1, 2));// 定义排版，一行三列
        panel.add(libJB);// 加入组件
        panel.add(codeJB);// 加入组件

        ButtonGroup group = new ButtonGroup();
        group.add(codeJB);
        group.add(libJB);
        add(panel);// 加入面板


        JPanel menu = new JPanel();
        menu.setLayout(new FlowLayout());
        Button cancel = new Button();
        cancel.setLabel("取消");
        cancel.addActionListener(actionListener);
        Button ok = new Button();
        ok.setLabel("确定");
        ok.addActionListener(actionListener);
        menu.add(cancel);
        menu.add(ok);
        add(menu);
    }

    private ActionListener actionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getActionCommand().equals("取消")) {
                closeListener.onClose();
            } else {
                closeListener.onClose();
                startInit();
            }
        }
    };

    /**
     * 开始初始化
     */
    private void startInit() {
        if (themeColor.getText() == null || !themeColor.getText().startsWith("#") || themeColor.getText().length() != 7) {
            showError("输入的主题颜色值有误");
            return;
        }
        if (appName.getText() == null) {
            showError("APP名称不能为空");
            return;
        }
        createBaseCode();
        rebuildApplication();
        createInitActivity();
        createMainActivity();
        // 自动刷新目录
        PathUtil.refreshProject(event);
        Messages.showInfoMessage(project, "初始化成功,请执行Reload Gradle Project", "提示");
    }

    private void createBaseCode() {
        createNewKotlinFile(appPath + "/ui/init", "InitCallBack");
        createNewKotlinFile(appPath + "/async", "LoadServiceAsyncTask");
        createNewKotlinFile(appPath + "/async", "WeakAsyncTask");
        createNewKotlinFile(appPath + "/common", "AppDirs");
        createNewKotlinFile(appPath + "/common", "GlobalService");
        createNewKotlinFile(appPath + "/common", "GlobalVars");
    }

    /**
     * 从框架读取并新建kotlin文件
     *
     * @param fileSavePath
     * @param fileName
     */
    private void createNewKotlinFile(String fileSavePath, String fileName) {
        String content = ReadFile(Constants.get(fileName), fileName + ".txt");
        content = dealDate(content);
        content = dealAppId(content);
        content = dealAppName(content);
        content = dealAuthor(content);
        FileUtils.reWriteFile(content, fileSavePath, fileName + ".kt");
    }

    /**
     * 新建MainActivity
     */
    private void createMainActivity() {
        createNewKotlinFile(appPath + "/ui/main/view", "MainActivity");
        createLayout("activity_main");
        writeActivityToManifest(appId + ".ui.main.view.MainActivity", false);
        createNewKotlinFile(appPath + "/ui/main/contract", "MainContract");
        createNewKotlinFile(appPath + "/ui/main/presenter", "MainPresenter");
        createNewKotlinFile(appPath + "/ui/main/model", "MainModel");
    }

    //创建InitActivity--->
    private void createInitActivity() {
        createNewKotlinFile(appPath + "/ui/init", "InitActivity");
        createLayout("activity_init");
        writeActivityToManifest(appId + ".ui.init.InitActivity", true);
    }

    /**
     * 新建layout
     *
     * @param layoutName
     */
    private void createLayout(String layoutName) {
        String layoutPath = project.getBasePath() + "/app/src/main/res/layout";
        String layoutContent = ReadFile(Constants.get(layoutName), layoutName + ".txt");
        layoutContent = dealAppId(layoutContent);
        FileUtils.reWriteFile(layoutContent, layoutPath, layoutName + ".xml");
    }


    /**
     * activity写入注册表
     *
     * @param activityFullPath activity完整包名
     * @param isLaunch         是否作为首个activity
     */
    private void writeActivityToManifest(String activityFullPath, boolean isLaunch) {
        String manifestPath = project.getBasePath() + "/app/src/main/AndroidManifest.xml";
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new InputSource(new FileInputStream(manifestPath)));
            Element activity = doc.createElement("activity");
            activity.setAttribute("android:name", activityFullPath);
            activity.setAttribute("android:exported", "true");
            if (isLaunch) {
                Element intentFilter = doc.createElement("intent-filter");
                Element action = doc.createElement("action");
                action.setAttribute("android:name", "android.intent.action.MAIN");
                intentFilter.appendChild(action);

                Element category = doc.createElement("category");
                category.setAttribute("android:name", "android.intent.category.LAUNCHER");
                intentFilter.appendChild(category);
                activity.appendChild(intentFilter);
            }
            Node node = doc.getElementsByTagName("application").item(0);
            node.appendChild(activity);
            Source sour = new DOMSource(doc);
            Result result = new StreamResult(new FileOutputStream(manifestPath));
            FileUtils.write(sour, result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建Application并写入manifest
     */
    private void rebuildApplication() {
        //新增color
        createColorValue();
        // 重写app_name
        reWriteAppName();
        //新建主题
        createStyle();
        //引入依赖
        importDependencies();
        //新建Application文件
        createNewKotlinFile(appPath, "MainApplication");
        //写入注册表
        writeApplicationToAndroidManifest();
        //修改根目录下gradle.properties
        editGradleProperties();
    }

    /**
     * 自动引入依赖
     */
    private void importDependencies() {
        try {
            //重写仓库地址
            String settingsGradlePath = project.getBasePath() + "/settings.gradle";
            String settingContent = FileUtils.readFileToString(settingsGradlePath);
            settingContent = settingContent.replace("mavenCentral()", "mavenCentral()\nmaven { url 'https://jitpack.io' }\n maven { url 'https://maven.google.com' }\njcenter()");
            FileUtils.reWriteFile(settingContent, project.getBasePath(), "settings.gradle");
            if (codeJB.isSelected()) {//setting中增加基础module的引用
                FileUtils.addToFile("\ninclude ':baselibrary'", project.getBasePath(), "settings.gradle");
            }
            //重写依赖文件
            String dependenciesPath = project.getBasePath() + "/app/";
            //优先读取线上的，读取失败再读取本地的
            String content = "";
            if (codeJB.isSelected()) {//源码方式依赖基础库--->下载基础库源代码
                content = ReadFile(Constants.dependencies1, "dependencies1.txt");
                File zipFile = HttpUtil.downloadFile(Constants.BaseLibraryCode, project.getBasePath());
                ZipUtils.unzip(zipFile, project.getBasePath());
                //TODO 删除zip文件
            } else {
                content = ReadFile(Constants.dependencies, "dependencies.txt");
            }
            FileUtils.reWriteFile(content, dependenciesPath, "dependencies.gradle");
            //重写app目录下的build.gradle文件
            String buildContent = ReadFile(Constants.appBuildGradle, "appBuildGradle.txt");
            buildContent = buildContent.replace("$appid", appId);
            FileUtils.reWriteFile(buildContent, dependenciesPath, "build.gradle");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void editGradleProperties() {
        String path = project.getBasePath();
        FileUtils.addToFile("\nandroid.enableJetifier=true", path, "gradle.properties");
    }

    /**
     * 处理包名
     *
     * @param content
     * @return
     */
    private String dealAppId(String content) {
        content = content.replace("$appId", appId);
        return content;
    }

    private String dealAppName(String content) {
        content = content.replace("$appName", appName.getText());
        return content;
    }

    private String dealAuthor(String content) {
        content = content.replace("$author", author.getText());
        return content;
    }

    /**
     * 处理时间
     *
     * @param content
     * @return
     */
    private String dealDate(String content) {
        content = content.replace("$date", DateUtil.getNowDateShort());
        return content;
    }

    /**
     * 新增color值
     */
    private void createColorValue() {
        String colorsPath = project.getBasePath() + "/app/src/main/res/values/colors.xml";
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new InputSource(new FileInputStream(colorsPath)));
            Element newEle = doc.createElement("color");
            newEle.setAttribute("name", "logoColor");
            newEle.setTextContent(themeColor.getText());
            Node node = doc.getElementsByTagName("resources").item(0);
            node.appendChild(newEle);
            Source sour = new DOMSource(doc);
            Result result = new StreamResult(new FileOutputStream(colorsPath));
            FileUtils.write(sour, result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建主题
     */
    private void createStyle() {
        String stylePath = project.getBasePath() + "/app/src/main/res/values/";
        String content = ReadFile(Constants.styles, "styles.xml");
        FileUtils.reWriteFile(content, stylePath, "styles.xml");
    }

    /**
     * 重写app_name
     */
    private void reWriteAppName() {
        String stringsPath = project.getBasePath() + "/app/src/main/res/values/strings.xml";
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new InputSource(new FileInputStream(stringsPath)));
            NodeList dogList = doc.getElementsByTagName("string");
            for (int i = 0; i < dogList.getLength(); i++) {
                Node dog = dogList.item(i);
                Element elem = (Element) dog;
                if (elem.getAttribute("name").equals("app_name")) {
                    elem.setTextContent(appName.getText());
                    Source sour = new DOMSource(doc);
                    Result result = new StreamResult(new FileOutputStream(stringsPath));
                    FileUtils.write(sour, result);
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void showError(String message) {
        Messages.showErrorDialog(project, message, "提示");
    }

    private String ReadFile(String fileUrl, String localFileName) {
        String result = HttpUtil.readRemoteFile(fileUrl);
        if (result == null) {
            InputStream in = null;
            in = this.getClass().getResourceAsStream("../Template/init/" + localFileName);
            String content = "";
            try {
                content = new String(FileUtils.readStream(in), "utf-8");
            } catch (Exception e) {
            }
            return content;
        } else {
            return result;
        }
    }


    /**
     * manifest 修改Application
     */
    private void writeApplicationToAndroidManifest() {
        String manifestPath = project.getBasePath() + "/app/src/main/AndroidManifest.xml";
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new InputSource(new FileInputStream(manifestPath)));
            NodeList dogList0 = doc.getElementsByTagName("manifest");
            //写入权限配置
            Node node = dogList0.item(0);
            Element permission1 = doc.createElement("uses-permission");
            permission1.setAttribute("android:name", "android.permission.WRITE_EXTERNAL_STORAGE");
            Element permission2 = doc.createElement("uses-permission");
            permission2.setAttribute("android:name", "android.permission.READ_EXTERNAL_STORAGE");
            Element permission3 = doc.createElement("uses-permission");
            permission3.setAttribute("android:name", "android.permission.INTERNET");
            node.appendChild(permission1);
            node.appendChild(permission2);
            node.appendChild(permission3);

            //写tools
            for (int i = 0; i < dogList0.getLength(); i++) {
                Node dog = dogList0.item(i);
                if (dog.getNodeType() == Node.ELEMENT_NODE) {
                    Element manifest = (Element) dog;
                    manifest.setAttribute("xmlns:tools", "http://schemas.android.com/tools");
                }
            }
            //重写appname style等
            NodeList dogList = doc.getElementsByTagName("application");
            for (int i = 0; i < dogList.getLength(); i++) {
                Node dog = dogList.item(i);
                if (dog.getNodeType() == Node.ELEMENT_NODE) {
                    Element application = (Element) dog;
                    application.setAttribute("android:name", appId + ".MainApplication");
                    application.setAttribute("android:theme", "@style/MyAppCompat");
                    application.setAttribute("tools:replace", "android:icon,android:theme");
                    // 移除不需要的参数
                    if (application.getAttribute("android:dataExtractionRules") != null) {
                        application.removeAttribute("android:dataExtractionRules");
                    }
                    if (application.getAttribute("android:fullBackupContent") != null) {
                        application.removeAttribute("android:fullBackupContent");
                    }
                    if (application.getAttribute("tools:targetApi") != null) {
                        application.removeAttribute("tools:targetApi");
                    }
                    if (application.getAttribute("android:supportsRtl") != null) {
                        application.removeAttribute("android:supportsRtl");
                    }

                }
            }
            Source sour = new DOMSource(doc);
            Result result = new StreamResult(new FileOutputStream(manifestPath));
            FileUtils.write(sour, result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
